﻿#ifndef GY_IDTREEVIEW_H
#define GY_IDTREEVIEW_H

#include <QTreeView>
#include <QStandardItemModel>
#include "GY_ControlLibrary_global.h"

class CustomFilterModule;
class GY_CONTROLLIBRARY_EXPORT GY_IdTreeView : public QTreeView
{
    Q_OBJECT

public:
    explicit GY_IdTreeView(QWidget *parent = nullptr);
    ~GY_IdTreeView();
    /**
     * @brief The TableDataType enum
     * 树数据类型枚举
     */
    enum TreeDataType
    {
        //!显示数据
        DisplayData=Qt::DisplayRole,
        //!复选框输数据
        CheckStateData=Qt::CheckStateRole,
        //!传输数据
        TransferData=Qt::UserRole+1,
        //!节点类型数据
        NodeTypeData,
        //!行Id数据
        RowIdData,
        //!包含的多级ID
        ContainMultileveID
    };
public:
//-------------------------列编辑接口--------------------------------
    /**
     * @brief setColumnCount 设置列数
     * @param columnCount 添加的列数
     */
    void setColumnCount(const int columnCount);
    /**
     * @brief addColumn 添加空白列
     * @param columnName 添加的列名
     */
    void addColumn(const QString &columnName);
    /**
     * @brief insterColumn 插入列
     * @param index 插入在第几列
     * @param columnName 插入的列名
     * @return 返回插入列是否成功
     */
    bool insertColumn(const int index, const QString &columnName);
    /**
     * @brief deleteColumn 删除列
     * @param index 删除的第几列
     * @return 返回删除列是否成功
     */
    bool deleteColumn(const int index);
    /**
     * @brief setColumnHeadName  设置列头名称
     * @param nameList  要修改的列名集
     */
    void setColumnHeadName(const QStringList &nameList);
    /**
     * @brief setColumnHeadName  修改某一列列名
     * @param index  要修改名字在第几列
     * @param headName  要修改成的名字
     */
    void setColumnHeadName(const int index,const QString &headName);
//-------------------------行编辑接口--------------------------------
    /**
     * @brief addRowData  添加行数据
     * @param rowId 行Id
     * @param rowData 行数据
     * @param nodeParentId 父级Id
     * @param nodeType 节点类型
     * @return 返回添加是否成功
     */
    virtual bool addRowData(const QVariant &rowId, const QVector<QVariant>&rowData, const QVariant &nodeParentId=QVariant(), const QVariant &nodeType=QVariant());
    /**
     * @brief insertRowData   插入行数据
     * @param rowId 节点id
     * @param rowData 插入的行数据
     * @param index 引索第几个
     * @param nodeParentId 父级Id
     * @param nodeType 节点类型
     * @return 返回插入行数据是否成功
     */
    virtual bool insertRowData(const QVariant &rowId, const QVector<QVariant>&rowData,const int index, const QVariant &nodeParentId=QVariant(), const QVariant nodeType=QVariant());
    /**
     * @brief deleteRow  删除指定行
     * @param id 删除行的id号
     * @return 返回删除是否成功
     */
    void deleteRow(const QVariant &rowId);
    /**
     * @brief clearData 清除数据
     */
    void clearData();
    /**
     * @brief getParentRowId 获取父级行Id
     * @param rowId 行Id
     * @return 父级行Id
     */
    QVariant getParentRowId(const QVariant &rowId);
    /**
     * @brief setRowData  修改行数据
     * @param rowId  修改行id
     * @param rowData  要修改的数据
     * @return 是否修改成功
     */
    bool setRowData(const QVariant &rowId, const QVector<QVariant>&rowData);
    /**
     * @brief setRowNodeType 设置节点类型
     * @param rowId 行ID
     * @param nodeType 节点类型
     * @return 是否设置成功
     */
    bool setRowNodeType(const QVariant &rowId,const QVariant &nodeType=QVariant());
    /**
     * @brief getNodeType 根据节点查找类型
     * @param rowId 行Id
     * @return 返回对应type
     */
    QVariant getRowNodeType(const QVariant &rowId);
    /**
     * @brief GY_IdTreeView::getRowData 获取行数据
     * @param rowId 行Id
     * @param rowData 返回的行数据
     * @return 成功/失败
     */
    bool getRowData(const QVariant &rowId, QVector<QVariant> &rowData);
    /**
     * @brief GY_IdTreeView::getRowIndex 获取行索引
     * @param rowId 行Id
     * @param index 所在父级下，该行的索引
     * @param parentRowId 父级rowId
     * @return 成功/失败
     */
    bool getRowIndex(const QVariant &rowId, int &index, QVariant &parentRowId);
//-------------------------单元格编辑接口--------------------------------
    /**
     * @brief setCellColor 修改item背景颜色
     * @param rowId 行id
     * @param columnIndex 列
     * @param color 颜色
     * @return 是否修改成功
     */
    bool setCellColor(const QVariant &rowId, const int columnIndex,const QColor& color);
    /**
     * @brief setCellData  修改单元格数据
     * @param rowId 修改行Id
     * @param columnIndex  修改列索引
     * @param cellData  要修改的数据
     * @param role 修改的数据类型
     * @return 是否修改成功
     */
    bool setCellData(const QVariant& rowId, const int columnIndex, const QVariant &cellData, int role=TreeDataType::TransferData);
    /**
     * @brief setCellText 设置单元格文字
     * @param rowId 行ID
     * @param columnIndex 列索引
     * @param displayText 显示文字
     * @return 是否设置成功
     */
    bool setCellText(const QVariant& rowId, const int columnIndex,const QString& displayText);
    /**
     * @brief getCellData
     * @param rowId 行ID
     * @param columnIndex 列索引
     * @param role 获取的数据类型
     * @return 单元格数据
     */
    QVariant getCellData(const QVariant& rowId, const int columnIndex,int role=TreeDataType::TransferData);
    /**
     * @brief getCellText 获取单元格文字
     * @param rowId 行ID
     * @param columnIndex 列索引
     * @return 单元格文字
     */
    QString getCellText(const QVariant& rowId, const int columnIndex);
    /**
     * @brief setCellEnabled 设置行交互状态
     * @param rowId  行ID
     * @param columnIndex 列索引
     * @param isEnabled 是否可交互
     * @return 返回设置是否成功
     */
    bool setCellEnabled(const QVariant &rowId, const int columnIndex, const bool isEnabled);
    /**
     * @brief setCellEditabled 设置行编辑状态
     * @param rowId  行ID
     * @param columnIndex 列索引
     * @param isEditabled 是否可编辑
     * @return 返回设置是否成功
     */
    bool setCellEditabled(const QVariant &rowId, const int columnIndex, const bool isEditabled);
//-------------------------过滤接口--------------------------------
    /**
     * @brief setFilterRegExp 设置搜索过滤正则表达式
     * @param searchText 搜索过滤文本
     */
    void setFilterRegExp(const QString &searchText);
//-------------------------图标接口--------------------------------
    /**
     * @brief setNodeTypeIcon 设置节点类型图标
     * @param nodeType 节点类型
     * @param icon 图标
     */
    void setNodeTypeIcon(const QVariant &nodeType,const QIcon& icon);
//-------------------------选择接口--------------------------------
    /**
     * @brief getSelecRowId  获取选择行id
     * @return  多选下返回选中的第一行
     */
    QVariant getSelectRowId();
    /**
     * @brief getSelectCellColunmindex 获取选择单元格索引
     * @return 返回选择单元格索引
     */
    int getSelectCellColunmIndex();
    /**
     * @brief getSelectRowIds 获取选择行id
     * @return  单选时返回一个id
     */
    QVector<QVariant> getSelectRowIds();
    /**
     * @brief setRowSelectState 设置行选择状态
     * @param rowId 节点ID
     * @param isSelect 该行是否选择
     * @return 是否设置成功
     */
    bool setRowSelectState(const QVariant &rowId,const bool isSelect);
//-----------------------------展开接口-----------------------------------------
    /**
     * @brief setRowExpendState 设置行单层展开模式
     * @param rowId  行id
     * @param isExpend 是否展开
     * @return 是否展开该行
     */
    bool setRowExpendState(const QVariant &rowId,const bool isExpend);
    /**
     * @brief setAllChildRowExpendState 设置所有子行展开状态
     * @param rowId  行ID
     * @param isExpend 是否展开
     * @return 是否展开该行
     */
    bool setAllChildRowExpendState(const QVariant &rowId,const bool isExpend);
    /**
     * @brief getExpentState 获取展开状态
     * @param rowId 行id
     * @return 返回是否展开
     */
    bool getExpentState(const QVariant &rowId);
    /**
     * @brief setAllRowExpendState  设置所有节点展开状态
     * @param isExpend true展开  false收起
     */
    void setAllRowExpendState(const bool isExpend);
//-----------------------------复选框接口-----------------------------------------
    /**
     * @brief setCheckable  设置是否显示复选框
     * @param isCheckable  ture显示 false不显示
     */
    void setCheckable(const bool isCheckable);
    /**
     * @brief getIsChecked 获取当前是否显示复选框
     * @return 返回是否显示复选框
     */
    bool getCheckable();
    /**
     * @brief getCheckedRowIds  获取选中的行id
     * @return 返回全部id
     */
    QVector<QVariant> getCheckedRowIds();
    /**
     * @brief setRowCheckState  设置复选框选中行状态
     * @param rowId  节点id
     * @param isCheck  是否选中
     * @return 返回该行是否被选中，true选中，false未被选中
     */
    bool setRowCheckState(const QVariant &rowId,const bool isCheck);
    /**
     * @brief getRowCheckState  获取复选框选中行状态
     * @param rowId  节点id
     * @param checkedState 选择状态
     * @return 是否获取成功
     */
    bool getRowCheckState(const QVariant &rowId, Qt::CheckState &checkedState);
    /**
     * @brief setTreeAllChecked 复选框全选/全不选
     * @param check 是否全选/全不选
     */
    void setTreeAllChecked(const bool isChecked);
protected:
    /**
     * @brief currentChanged 当前选择变化
     * @param current 当前选择的索引
     * @param previous 之前选择的索引
     */
    void currentChanged(const QModelIndex &current,const QModelIndex &previous) override;
    /**
     * @brief setAllChildNodeExpentState 设置所有子节点展开状态
     * @param pItem 当前节点的Item
     * @param isExpend 是否展开
     */
    void setAllChildNodeExpentState(QStandardItem *pItem, bool isExpend);
    /**
     * @brief updateTopParentNodeExpentState 跟新递归至顶层的所有父级节点的展开状态
     * @param pItem 当前节点item
     */
    void updateTopParentNodeExpentState(QStandardItem *pItem);
    /**
     * @brief setAllchildNodeCheckState 设置所有子节点的复选框状态
     * @param pItem 节点对象
     */
    void setAllchildNodeCheckState(QStandardItem *pItem);
    /**
     * @brief updateTopParentNodeCheckState 更新递归至顶层的所有父级节点的复选状态
     * @param pItem 当前节点item
     */
    void updateTopParentNodeCheckState(QStandardItem *pItem);

protected slots:
    /**
     * @brief cellDataChangeSlot 单元格数据改变
     * @param topLeft  左上索引以
     * @param bottomRight 右下索引
     * @param roles 数据类型
     */
    void cellDataChangeSlot(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
protected:
    //! 节点信息Map
    QMap<QVariant,QList<QStandardItem*>> m_TreeNodeInfo;
    //! 类型和图标map
    QMap<QVariant,QIcon> m_NodeTypeToIconMap;
    //! 标准模型指针
    QStandardItemModel* m_pModel;
    //! 自定义过滤组件
    CustomFilterModule* m_pFilter;
    //! 是否开启复选框
    bool m_IsCheckable;
signals:
    /**
     * @brief selectRowChangeSignal 选择行改变信号
     * @param rowId 行id
     */
    void selectRowChangeSignal(const QVariant &rowId);
    /**
     * @brief selectCellChangeSignal 选择单元格改变信号
     * @param rowId
     * @param columnIndex
     */
    void selectCellChangeSignal(const QVariant &rowId,const int columnIndex);
    /**
     * @brief sgl_CellValueChange 单元格值改变信号
     * @param rowId 行号
     * @param columnIndex 列索引
     * @param value 单元格改变后的值
     * @return 操作结果码
     */
    int sgl_CellValueChange(const QVariant &rowId, qint32 columnIndex, const QVariant &value);
};

#endif // GY_IDTREEVIEW_H
